package server;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.lang.*;

/**
 * <p>Title: HttpdConf.java</p>
 *
 * <p>Description: This class will configure your server to the specifications
 * found within the httpd.conf file. </p>
 *
 * <p>Copyright: Copyright (c) 2005</p>
 *
 * <p>Company: </p>
 * @author Luping May and Tracie Hong
 * @version 1.0
 */
public class HttpdConf {
  private String ServerRoot;
  private String ServerAdmin;
  private String DocumentRoot;
  private String LogFile;
  private String UpLoad;
  private static Hashtable <String, String> ScriptAlias;
  private static Hashtable <String, String> Alias;
  private String TempDirectory;
  private int listen ;
  private int MaxThread;
  private boolean CacheEnabled;
  private boolean PersistentConnection;
  private Vector <String> DirectoryIndex;
  private String AccessFileName;
  private static Hashtable <String, String> MIMEtable;
  private static Hashtable <String, String> CgiHandler;
  private Vector <ForAuth> Authentication = new Vector();
  private Vector <String> ScriptExtension;

  /**
   * Default constructor to reset your variables and data structures.
   */

  public HttpdConf(){
    ServerRoot = null;
    ServerAdmin = null;
    DocumentRoot = null;
    LogFile = null;
    UpLoad = null;
    Alias = new Hashtable <String, String>();
    ScriptAlias = new Hashtable <String, String>();
    TempDirectory = null;
    listen = 80;
    MaxThread = 0;
    CacheEnabled = false;
    PersistentConnection = false;
    DirectoryIndex = new Vector <String>();
    AccessFileName = null;
    MIMEtable = new Hashtable <String, String>();
    CgiHandler = new Hashtable <String, String>();
    ScriptExtension = new Vector();
  }

  /**
   * Reads in a httpd.conf file, parses it and saves the data stored within that
   * file. This allows for proper configuration of your server since the
   * information stored in your configuration file should allow for your server
   * to function.
   *
   * @param path path to your httpd.conf file
   */
  public void readHttpd(String path){

    try{
        String temp1 = "";
        String temp2 = "";
        String readConf;
        StringTokenizer confAnalysis;
        String confToken;
        BufferedReader in = new BufferedReader(new FileReader(path));
        while(in.ready()){
            readConf = in.readLine();
            //System.out.println(readConf);
            if(readConf.trim().length() != 0){
                confAnalysis = new StringTokenizer(readConf);
                confToken = confAnalysis.nextToken();
                if(!confToken.equals("#")){
                    if(confToken.equalsIgnoreCase("ServerRoot")){
                        temp1 = confAnalysis.nextToken();
                        ServerRoot = temp1.substring(1, temp1.length()-1);
                    }

                    else if(confToken.equalsIgnoreCase("ServerAdmin")){
                        ServerAdmin = confAnalysis.nextToken();
                    }

                    else if(confToken.equalsIgnoreCase("DocumentRoot")){
                        temp1 = confAnalysis.nextToken();
                        DocumentRoot = temp1.substring(1, temp1.length()-1);
                    }

                    else if(confToken.equalsIgnoreCase("LogFile")){
                        temp1 = confAnalysis.nextToken();
                        LogFile = temp1.substring(1, temp1.length()-1);
                    }

                    else if(confToken.equalsIgnoreCase("UpLoad")){
                        temp1 = confAnalysis.nextToken();
                        UpLoad = temp1.substring(1, temp1.length()-1);
                    }
                    
                    else if(confToken.equalsIgnoreCase("TempDirectory")){
                        temp1 = confAnalysis.nextToken();
                        TempDirectory = temp1.substring(1, temp1.length()-1);
                    }

                    else if(confToken.equalsIgnoreCase("Listen")){
                        listen = Integer.parseInt(confAnalysis.nextToken());
                    }


                    else if(confToken.equalsIgnoreCase("MaxThread")){
                        MaxThread = Integer.parseInt(confAnalysis.nextToken());
                    }

                    else if(confToken.equalsIgnoreCase("CacheEnabled")){
                        if(confAnalysis.nextToken().equalsIgnoreCase("ON"))
                            CacheEnabled = true;
                        else
                            CacheEnabled = false;
                    }

                    else if(confToken.equalsIgnoreCase("PersistentConnection")){
                        if(confAnalysis.nextToken().equalsIgnoreCase("ON"))
                            PersistentConnection = true;
                        else
                            PersistentConnection = false;
                    }

                    else if(confToken.equalsIgnoreCase("DirectoryIndex")){
                        while(confAnalysis.hasMoreElements())
                        {
                            DirectoryIndex.add(confAnalysis.nextToken());
                        }
                    }

                    else if(confToken.equalsIgnoreCase("ScriptAlias")){
                        temp1 = confAnalysis.nextToken();
                        temp1 = temp1.substring(0, temp1.length()-1);
                        temp2 = confAnalysis.nextToken();
                        temp2 = temp2.substring(1, temp2.length()-1);
                        ScriptAlias.put(temp1, temp2);
                    }

                    else if(confToken.equalsIgnoreCase("Alias")){
                        temp1 = confAnalysis.nextToken();
                        temp2 = confAnalysis.nextToken();
                        temp2 = temp2.substring(1, temp2.length()-1);
                        Alias.put(temp1, temp2);
                    }

                    else if(confToken.equalsIgnoreCase("CgiHandler")){
                        temp2 = confAnalysis.nextToken();
                        temp2 = temp2.substring(1, temp2.length()-1);
                        temp1 = confAnalysis.nextToken();
                        ScriptExtension.add(temp1);
                        CgiHandler.put(temp1, temp2);
                    }
                    else if (confToken.equalsIgnoreCase("<Directory")){
                        //System.out.println("directory");
                        temp1 = confAnalysis.nextToken();
                        ForAuth auth = new ForAuth();
                        auth.setDirectory(temp1.substring(1, temp1.length()-4));
                        readConf = in.readLine();
                        while(!readConf.trim().equals("</Directory>")){
                               if(readConf.trim().length() != 0){
                                confAnalysis = new StringTokenizer(readConf);
                                confToken = confAnalysis.nextToken();
                                if(confToken.equalsIgnoreCase("AuthName")){
                                    temp1 = confAnalysis.nextToken();
                                    auth.setAuthName(temp1.substring(1,temp1.length()-1));
                                }
                                else if (confToken.equalsIgnoreCase("AuthType")){
                                    temp1 = confAnalysis.nextToken();
                                    auth.setAuthType(temp1);
                                }
                                else if (confToken.equalsIgnoreCase("require")){
                                    temp1 = confAnalysis.nextToken();
                                    if (!temp1.equals("valid-user"))
                                        auth.setRequire(confAnalysis.nextToken());
                                }
                                else if (confToken.equalsIgnoreCase("AuthUserFile")){
                                    temp1 = confAnalysis.nextToken();
                                    auth.setAuthUserFile(temp1.substring(1,temp1.length()-1));
                                }
                              }
                               readConf = in.readLine();
                        }
                               Authentication.add(auth);
                    }

                }
            }
        }
        //testPrint();
    }catch(IOException e){
        System.err.println("Error: " + e.getMessage());
    }
  }

  /**
   * Function to convert aliases set within your httpd.conf file to their
   * absolute path. This allows for aliases to be found on your server and
   * returned back to the client.
   * HINT: You may find it helpful to create a private class to store your
   * aliases.
   *
   * @param fakeName String which contains the alias of the file or directory
   * @return String value which contains the absolute path to the file or
   *   directory as determined within the httpd.conf file
   */
  public String solveAlias(String fakeName){
    if(isScript(fakeName)){
        return ScriptAlias.get(fakeName);
    }
    return Alias.get(fakeName);
  }

  /**
   * Used to read the mime.types file and save all the information from that file
   * into a data structure that can be used to validate file types when
   * generating response messages.
   *
   * @param path String value of path to mime.types file
   */
  public void readMIME (String path) {
    try{
        String readMIME;
        StringTokenizer sTokenizer;
        String MIMEtype;
        BufferedReader in = new BufferedReader(new FileReader(path));
        while(in.ready()){
            readMIME = in.readLine();
            if(readMIME.trim().length() != 0){
                sTokenizer = new StringTokenizer(readMIME);
                MIMEtype = sTokenizer.nextToken();
                if(!MIMEtype.equals("#")){
                    while(sTokenizer.hasMoreTokens()){
                        MIMEtable.put(sTokenizer.nextToken(), MIMEtype);
                    }
                }
            }
        }
    }catch(IOException e){
        System.err.println("Error: " + e.getMessage());
    }
  }

  /**
   * Helper function to determine whether the name of a file or directory is an
   * alias for another file or directory as noted in the httpd.conf file.
   *
   * @param name String value of the alias we want to check to determine
   *   whether it is or is not an alias for another file or directory
   * @return true if it is an alias, false otherwise
   */
  public boolean isScript(String name)	{
    if(ScriptAlias.containsKey(name)){
        return true;
    }
    return false;
  }

  /**
   * Helper function to see if you've parsed your httpd.conf file properly. Used
   * for debugging purposes.
   */
  public void testPrint(){
    System.out.println("ServerRoot: "+ServerRoot);
    System.out.println("DocumentRoot: "+DocumentRoot);
    System.out.println("ListenPort: "+listen);
    System.out.println("LogFile: "+LogFile);
    System.out.println("UpLoad: "+UpLoad);
    System.out.println("MaxThread: "+MaxThread);
    System.out.println("/cgi-bin/: " + ScriptAlias.get("/cgi-bin/"));
    System.out.println("mp3: " + MIMEtable.get("mp3"));
    System.out.println("AccessFileName: " + AccessFileName);
    System.out.println(".pl: " + " "+ CgiHandler.get(".pl"));
  }


  public String getServerRoot(){return ServerRoot;}
  public String getServerAdmin(){return ServerAdmin;}
  public String getDocumentRoot(){return DocumentRoot;}
  public String getLogFile(){return LogFile;}
  public String getUpLoad(){return UpLoad;}
  public String getTempDirectory(){return TempDirectory;}
  public int getListen(){return listen;}
  public int getMaxThread(){return MaxThread;}
  public boolean isCacheEnabled(){return CacheEnabled;}
  public boolean isPersistentConnection(){return PersistentConnection;}
  public Vector getDirectoryIndex(){return DirectoryIndex;}
  public String getAccessFileName(){return AccessFileName;}
  public Hashtable getMIMEtable(){return MIMEtable;}
  public String getCGIHandler(String extension){
      extension = extension.substring(extension.indexOf("."),extension.length());
      return CgiHandler.get(extension);
  }
  public Vector getAuthentication(){return Authentication;}
  public Vector getScriptExtension(){return ScriptExtension;}
}
